/*
 *  Datagrid Framework
 *  version 0.41
 *  Abe Yang <abeyang@cal.berkeley.edu> (c) 2006 
/*--------------------------------------------------------------------------*/

/*
	Issues:
	* ie: outer div showing
	* corner: blank
	* safari: leftcol missing right border
	* ff: toprow missing left border
	
	Todo:
	* mouse scrolling	
	* dynamic resize
	* alternate row colors: flag
*/
	
var isIE = navigator.appVersion.match(/\bMSIE\b/);
var isSafari = /Konqueror|Safari|KHTML/.test(navigator.userAgent);
var isWindows = /Windows/.test(navigator.userAgent);	// ff in windows and mac are a bit different..

// Fixes the scroll noticing in prototype
Position.includeScrollOffsets = true;

// Datagrid class
var Datagrid = Class.create();
Datagrid.prototype = {
	/*--------------------------------------------------------------------------
	 * datagrid variables
	/*--------------------------------------------------------------------------*/
	initialize: function(id, options) {
		this.id = 			id;
		this.header = 		options.header;
		this.leftcolumn = 	options.leftcolumn;
		this.data = 		options.data;
		this.height = 		options.height || 400;
		this.width = 		options.width || 600;
		this.maxleftwidth = options.maxleftwidth || 200;
		this.replace = 		options.replace;	
		this.hasstripes = 	options.hasstripes || true;
		//this.isresizeable = options.isresizeable || false;
		this.isresizeable = false;	// TODO: not ready for primetime yet
		
		this.creationsuccess = false;

		this.scroll_width = 15;
		if (isIE) this.scroll_width = 18;
		else if (isWindows) this.scroll_width = 19;
		
		// create grid
		this.create();
		if (this.creationsuccess) {
			// event handler for scrolling
			Event.observe($(this.id + '-scroll'), 'scroll', function(event) {
				$(this.id + '-left-column').scrollTop = $(this.id + '-cells').scrollTop = $(this.id + '-scroll').scrollTop;
			}.bindAsEventListener(this));
			if (this.isresizeable) {
				this.windowresize();
				Event.observe(window, 'resize', this.windowresize.bindAsEventListener(this));
			}
			else this.resize(this.width, this.height);
		}
	},
	
	version: '0.41',
	
	/*--------------------------------------------------------------------------
	 * core functions
	/*--------------------------------------------------------------------------*/

	create: function() {
		// set default variables
		var id = this.id;
		var c = $(id);	// container
		var header = this.header;
		var leftcolumn = this.leftcolumn;
		var data = this.data;
		var h = this.height;
		var w = this.width;
		var replace = this.replace;

		// check options
		/* header */
		if (header == null) { alert('No *header* in options'); return; }
		else if (typeof(header) != 'object') { alert('*header* must be an array'); return; }

		/* leftcolumn */
		if (leftcolumn == null) { alert('No *leftcolumn* in options'); return; }
		else if (typeof(leftcolumn) != 'object') { alert('*leftcolumn* must be an array'); return; }

		/* data */
		if (data == null) { alert('No *data* in options'); return; }
		else if (typeof(data) != 'object') { alert('*data* must be an array'); return; }

		// fill in tables
		var r = 1;
		var d = 1;

		/* header */
		var headerstr = '<tbody><tr>';
		header.each(function(str) {
			headerstr += '<th id="' + id + '-top-' + d + '"><div>' + str + '</div></th>';
			d++;
		});
		headerstr += '</tr></tbody>';

		/* leftcolumn */
		var leftcolstr = "";
		leftcolumn.each(function(str) {
			thisclass = Datagrid.U.stripe(r);
			leftcolstr += '<tr><td id="' + id + '-left-' + r + '"' + thisclass + '>' + str + "</td></tr>";
			r++;
		});

		r = 1;
		var datastr = '';
		data.each(function(row) {
/*			console.log	(this);*/
			d = 1;
			datastr += '<tr id="' + id + '-row-' + r + '">'
			row.each(function(datum) {
				thisclass = Datagrid.U.stripe(r);
				output = (replace == null || replace[datum] == null) ? datum : replace[datum];
				datastr += '<td id="' + id + '-cell-' + r + '-' + d + '"' + thisclass + '>' + output + '</td>';
				d++;
			});
			datastr += '</tr>'
			r++;
		});

		// create giant wrapper
		var html = "\n" +
			"<div id=\"" + id + "-nsc\" class=\"gridNoScrollContainer\" style=\"position:relative; width:" + w + "; height:" + h + ";\">\n" +
				"\t<div id=\"" + id + "-corner\" class=\"gridCorner\" style=\"position: relative;\">&nbsp;</div>\n" +
					"\t\t<div id=\"" + id + "-left-column\" class=\"gridLeftColumn\">\n" +
						"\t\t\t<table id=\"" + id + "-left-column-table\" style=\"width: " + this.maxleftwidth + "px\">" + leftcolstr + "</table>\n" + 
					"\t\t</div>\n" +
			   		"\t\t<div id=\"" + id + "-container\" class=\"gridContainer\">\n" +
			   			"\t\t\t<div id=\"" + id + "-top-row\" class=\"gridTopRow\">\n" + 
							"\t\t\t\t<table id=\"" + id + "-top-row-table\">" + headerstr + "</table>\n" + 
						"\t\t\t</div>\n" +
			   			"\t\t\t<div id=\"" + id + "-cells\" class=\"gridCells\"\n>" + 
							"\t\t\t\t<table id=\"" + id + "-cells-table\">\n" + datastr + "</table>\n" + 
						"\t\t\t</div>\n" + 
					"\t\t</div>\n" + 
				"\t</div>\n" +
			"</div>" +
			"<div id=\"" + id + "-scroll\" class=\"gridScroller\" style=\"width: " + this.scroll_width + "px\">" + 
				"<div id=\"" + id + "-scroll-height\" class=\"gridScrollHeight\"></div>" + 
			"</div>";

		c.innerHTML = html;
		
		// match cell widths
		var leftcol_t = $(id + '-left-column-table');
		var toprow_t = $(id + '-top-row-table');
		var cells_t = $(id + '-cells-table');
		
		var i = 1;
		var toprow_items = $A(toprow_t.getElementsByTagName('th'));
		toprow_items.each(function(item) {
			div_elem = item.childNodes[0];	// grab div element in td cell
			Datagrid.U.greaterSize(div_elem, $(id + '-cell-' + '1-' + i), 'w', i);
			i++;
		});
		Datagrid.U.greaterSize(toprow_t, cells_t, 'w', 0);	// must adjust tables as well

		// match cell heights
		i = 1;
		leftcol_items = $A(leftcol_t.getElementsByTagName('td'));
		leftcol_items.each(function(item) {
			// IE: must compare rows (rather than cells)
			if (isIE) Datagrid.U.greaterSize(item, $(id + '-row-' + i), 'h', i);
			else Datagrid.U.greaterSize(item, $(id + '-cell-' + i + '-1'), 'h', i);
			i++;
		});
		Datagrid.U.greaterSize(leftcol_t, cells_t, 'h', 0);	// must adjust tables as well
		
		this.creationsuccess = true;
	},

	resize: function(w, h) {
		// unfortunately, in the loops to come, "this" no longer refers to this object (Datagrid),
		// but rather the window. Thus, we must copy over the fn "greaterSize"...
		//greaterSize = this.greaterSize;

		// set vars	
		var id = this.id;
		var delta = isSafari ? 0 : 1;
		var scroll_width = this.scroll_width;

		var elem = $(id);
		var nsc = $(id + '-nsc');
		var container = $(id + '-container');
		var leftcol = $(id + '-left-column');
		var toprow = $(id + '-top-row');
		var corner = $(id + '-corner');
		var cells = $(id + '-cells');

		var leftcol_t = $(id + '-left-column-table');
		var toprow_t = $(id + '-top-row-table');
		var cells_t = $(id + '-cells-table');
		var corner_t = $(id + '-corner-table');
		
		var scroller = $(id + '-scroll');
		var scroll_h = $(id + '-scroll-height');

		// set master container's dimensions
		elem.style.width = w + 'px';
		elem.style.height = h + 'px';

		// determine height of containers/tables
		var heightof = new Array();
		heightof['toprow_t'] = Element.getHeight(toprow_t);
		heightof['leftcol_t'] = Element.getHeight(leftcol_t);
		heightof['total_t'] = heightof['toprow_t'] + heightof['leftcol_t'];
		// determine width of containers/tables
		var width_arr = new Array();
		width_arr['toprow_t'] =   toprow_t.offsetWidth;
		width_arr['leftcol_t'] = leftcol_t.offsetWidth;
		width_arr['total_t'] = width_arr['toprow_t'] + width_arr['leftcol_t'];

		// TODO: above this line should not be a part of resize... 
		
		nscPos = Position.cumulativeOffset(nsc);
		//$('log').innerHTML = nscPos[0] + ' ' + nscPos[1] + ' ' + leftcol.offsetWidth;

		// set dimensions of...

		/* container*/
		container.style.width = w - width_arr['leftcol_t'] + 'px';
		container.style.height = h + 'px';

		/* left column */
		leftcol.style.width = width_arr['leftcol_t'] - delta + 'px';
		leftcol.style.height = h - heightof['toprow_t'] - scroll_width + 'px';
		
		leftcol.style.position = 'absolute';
		leftcol.style.top = heightof['toprow_t'] - 1 + 'px';

		/* cells */
		cells.style.width = width_arr['toprow_t'] + 'px';
		cells.style.height = leftcol.style.height;

		/* scroller */
		scroll_height = heightof['leftcol_t'] + delta;
		scroll_height += (isSafari || isIE) ? 0 : scroll_width;	// adjust for ff
		scroll_h.style.height = scroll_height + 'px';
		scroller.style.height = h - heightof['toprow_t'] + 'px';

		// set placement of...
		/* container */
		container.style.position = 'absolute';
		container.style.top = '0';
		container.style.left = leftcol.offsetWidth + 'px';

		/* scroller */
		scroller.style.position = 'absolute';
		// Safari requires Position.positionedOffset; doesn't work correct with a simple offsetTop/Left
		scroller.style.top = Position.positionedOffset(nsc)[1] + heightof['toprow_t'] + 'px';
		scroller.style.left = Position.positionedOffset(nsc)[0] + w + 'px';

		// outside container's height:
		$(id).style.height = nsc.style.height = h + "px";
	},
	
	windowresize: function() {
		//console.log(this);
		//this.resize(document.body.clientWidth - this.scroll_width, document.body.clientHeight);
		this.resize(document.body.clientWidth - this.scroll_width, window.innerHeight - 2 * this.scroll_width);
	}
	
};

/*--------------------------------------------------------------------------
 * utility functions
/*--------------------------------------------------------------------------*/
Datagrid.U = {
	// ex: "14px" => 14 (string to number)
	toNumber: function(str) {
		return Number(str.substring(0,str.length-2));
	},
	
	// for adding stripes
	stripe: function(rownum) {
		return (rownum & 1) ? '' : ' class="stripe"';
	},
	
	// compares the size of two elements (by width or height); 
	// sets the smaller one to the bigger size
	greaterSize: function(node, datumnode, flag, currentrow) {
		if (flag == 'w') {
			if (node.offsetWidth >= datumnode.offsetWidth) {
				w = node.offsetWidth;
			}
			else {
				w = datumnode.offsetWidth;	
			}
			node.style.width = w + "px";
			// must add 1 px for Safari (for data cells only)
			if (isSafari) w++;
			datumnode.style.width = w + "px";
	/*		console.log("node: " + node.offsetWidth + " | datumnode: " + datumnode.offsetWidth);*/
		}
		else if (flag == 'h') {
	/*		$('log').innerHTML += "<br />" + currentrow + " node: " + node.offsetHeight + " | datumnode: " + datumnode.offsetHeight;*/
			if (node.offsetHeight >= datumnode.offsetHeight) {
				h = node.offsetHeight;
			}
			else {
				h = datumnode.offsetHeight;
			}
			datumnode.style.height = node.style.height = h + "px";
	/*		$('log').innerHTML += "|| node: " + node.offsetHeight + "," + node.style.height + " | datumnode: " + datumnode.offsetHeight + "," + datumnode.style.height;*/
		}
		else {
			// throw error?
		}
	}
};
